package com.blb.nio;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.util.Iterator;

/**
 * NIO模型服务器
 */
public class NIOServer {

    public static final int PORT = 8888;

    public void start() throws IOException {
        //获得服务器端socket的通道
        ServerSocketChannel ssc = ServerSocketChannel.open();
        //设置为非阻塞式
        ssc.configureBlocking(false);
        //绑定某个端口
        ssc.socket().bind(new InetSocketAddress(PORT));
        //创建多路复用器
        Selector selector = Selector.open();
        //注册获得客户端连接的事件
        ssc.register(selector, SelectionKey.OP_ACCEPT);
        while(true){
            // 执行事件轮询，看是否能获得客户端信息
            selector.select();
            System.out.println("有客户端连接事件发生");
            // 获得连接事件的迭代器
            Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();
            // 遍历迭代器
            while(iterator.hasNext()){
                SelectionKey key = iterator.next();
                //删除当前key
                iterator.remove();
                //处理当前时间的key
                handle(key);
            }
        }
    }

    /**
     * 处理客户端的事件
     * @param key
     */
    private void handle(SelectionKey key) throws IOException {
        //判断如果是接收客户端事件
        if(key.isAcceptable()){
            System.out.println("客户端连接事件");
            //获得客户端的连接通道
            ServerSocketChannel channel = (ServerSocketChannel) key.channel();
            SocketChannel accept = channel.accept();
            //设置非阻塞
            accept.configureBlocking(false);
            //注册读事件
            accept.register(key.selector(),SelectionKey.OP_READ);
        }else if(key.isReadable()){
            System.out.println("客户端读取事件");
            //如果是读取客户端事件
            SocketChannel channel = (SocketChannel) key.channel();
            //创建缓冲区
            ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
            //把数据读到缓冲区内部
            int read = channel.read(byteBuffer);
            if(read != -1){
                //显示缓存区中的数据
                String msg = new String(byteBuffer.array(), 0, read);
                System.out.println("读取客户端的消息：" + msg);
            }
            //返回消息给客户端，将数据存入缓冲区
            ByteBuffer buffer = ByteBuffer.wrap("Hello!!我是服务器".getBytes());
            channel.write(buffer);
            //注册客户端的读写事件
            key.interestOps(SelectionKey.OP_READ | SelectionKey.OP_WRITE);
        }else if(key.isWritable()){
            //如果是客户端的写事件
            System.out.println("客户端写入事件");
            SocketChannel channel = (SocketChannel) key.channel();
            //注册读客户端事件
            key.interestOps(SelectionKey.OP_READ);
        }
    }

    public static void main(String[] args) throws IOException {
        new NIOServer().start();
    }
}
